package org.imaginedays.androidall.fragment;

import java.util.ArrayList;
import java.util.List;

import org.imaginedays.androidall.R;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ArrayAdapter;

public class TestListFragment extends ListFragment {

    public static TestListFragment newInstance() {
        return new TestListFragment();
    }

    private ArrayAdapter<String> adapter;
    private static final int LOADER_ID = 0;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        setHasOptionsMenu(true);

        setEmptyText("empty");

        adapter = new ArrayAdapter<String>(getActivity(), R.layout.list_column, R.id.text);
        setListAdapter(adapter);

        load(false);
    }

    /**
     * 読込開始
     */
    private void load(boolean forceLoad) {
        Log.d(getClass().getName(), "[load]forceLoad=" + forceLoad);

        // 読込アニメーション開始
        setListShown(false);

        if (forceLoad) {
            // これだとキャンセル後の再読込が走らない
            // getLoaderManager().restartLoader(LOADER_ID, null, loaderCallback);

            Loader<List<String>> loader = getLoaderManager().getLoader(LOADER_ID);
            if (loader != null) {
                loader.forceLoad();
            }
        } else {
            // 読込済データあれば再利用
            getLoaderManager().initLoader(LOADER_ID, null, loaderCallback);
        }
    }

    /**
     * 読込キャンセル
     */
    private void loadCancel() {
        // 読込アニメーション開始
        setListShown(true);

        //TODO キャンセル処理
        // Loader#stopLoading、AsyncTaskLoader#cancelLoad を絡めるとまともに動かなくなる。
        // onCreateLoader 後に onStartLoading が呼ばれないので読込処理にもいかない。

        // 読込キャンセル
        Loader<List<String>> loader = getLoaderManager().getLoader(LOADER_ID);
        if (loader != null) {
            Log.d(getClass().getName(), "[loadCancel]");
            ((AsyncTaskLoader<List<String>>) loader).cancelLoad();
        }
    }

    // Adapterに依存
    private LoaderManager.LoaderCallbacks<List<String>> loaderCallback = new LoaderCallbacks<List<String>>() {

        @Override
        public Loader<List<String>> onCreateLoader(int id, Bundle args) {
            Log.d(getClass().getName(), "[onCreateLoader]");
            // LOADER_ID が存在しない場合に呼び出される
            return new TestLoader(getActivity());
        }

        @Override
        public void onLoadFinished(Loader<List<String>> loader, List<String> data) {
            Log.d(getClass().getName(), "[onLoadFinished]");
            if (adapter != null) {
                adapter.clear();
                adapter.addAll(data);
            }

            // 読込アニメーション終了
            stopLoadAnimation();
        }

        @Override
        public void onLoaderReset(Loader<List<String>> loader) {
            Log.d(getClass().getName(), "[onLoaderReset]");
            if (adapter != null) {
                adapter.clear();
            }
        }

        private void stopLoadAnimation() {
            if (isResumed()) {
                // 表
                setListShown(true);
            } else {
                // 裏(onPause中)
                setListShownNoAnimation(true);
            }
        }
    };

    private static class TestLoader extends AsyncTaskLoader<List<String>> {

        public TestLoader(Context context) {
            super(context);
        }

        private List<String> loadData;

        @Override
        protected void onStartLoading() {
            if (loadData != null) {
                Log.d(getClass().getName(), "[onStartLoading]exists");
                deliverResult(loadData);
            } else {
                Log.d(getClass().getName(), "[onStartLoading]load");
                forceLoad();
            }
        }

        @Override
        public List<String> loadInBackground() {
            Log.d(getClass().getName(), "[loadInBackground]");
            // 読込開始
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            loadData = createLoadData();
            return loadData;
        }

        private List<String> createLoadData() {
            List<String> data = new ArrayList<String>();
            for (int i = 0; i < 100; i++) {
                data.add("[" + i + "]" + System.currentTimeMillis());
            }
            return data;
        }

        @Override
        protected void onReset() {
            Log.d(getClass().getName(), "[onReset]");
            super.onReset();

            // loader停止処理
            onStopLoading();

            if (loadData != null) {
                loadData = null;
            }
        }

        @Override
        protected void onStopLoading() {
            Log.d(getClass().getName(), "[onStopLoading]");
            super.onStopLoading();

            // 読込キャンセル
            cancelLoad();
        }

        @Override
        public void onCanceled(List<String> data) {
            Log.d(getClass().getName(), "[onCanceled]");
            super.onCanceled(data);
        }

        @Override
        protected void onAbandon() {
            Log.d(getClass().getName(), "[onAbandon]");
            super.onAbandon();
        }
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        MenuItem load = menu.add(0, ActionType.LOAD.getId(), Menu.NONE, "load");
        load.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

        MenuItem reload = menu.add(0, ActionType.LOAD_FORCE.getId(), Menu.NONE, "load(force)");
        reload.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

        MenuItem cancel = menu.add(0, ActionType.CANCEL.getId(), Menu.NONE, "cancel");
        cancel.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        ActionType actionType = ActionType.valudOf(item.getItemId());
        switch (actionType) {
        case LOAD:
            load(false);
            break;
        case LOAD_FORCE:
            load(true);
            break;
        case CANCEL:
            loadCancel();
            break;
        }
        return super.onOptionsItemSelected(item);
    }

    private enum ActionType {
        NONE(-1),
        LOAD(0),
        LOAD_FORCE(1),
        CANCEL(2);

        private int id;

        private ActionType(int id) {
            this.id = id;
        }

        public int getId() {
            return id;
        }

        public static ActionType valudOf(int id) {
            for (ActionType type : values()) {
                if (type.getId() == id) {
                    return type;
                }
            }
            return NONE;
        }
    }
}
